package com.scorekeeper.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;

import com.scorekeeper.objects.Division;
import com.scorekeeper.objects.Extension;
import com.scorekeeper.objects.Game;
import com.scorekeeper.objects.Season;
import com.scorekeeper.objects.Team;
import com.scorekeeper.utils.DBProvider.Table;

@SuppressWarnings("unchecked")
public class Loader {
	DBProvider db = null;
	
	public Loader() {
		db = new DBProvider();
	}
	
/** 
 * GAMES 
 * **/
	
	public Map<Long, Game> loadGames(int teamId) {
		Object obj = db.loadObject(DBProvider.Table.GAME, 0, teamId);
		if (obj != null) 
			return (Map<Long, Game>) obj;
		else
			return null;
	}
	
	public Map<Long, Game> loadGames() {
		Object obj = db.loadObject(DBProvider.Table.GAME, 0, 0);
		if (obj != null) 
			return (Map<Long, Game>) obj;
		else
			return null;
	}
	
	public Game loadGame(int gameId) {
		Object obj = db.loadObject(DBProvider.Table.GAME, gameId, 0);
		if (obj != null)
			return (Game) obj;
		else
			return null;
	}
	
/** 
 * TEAMS 
 * **/
	
	public Team loadTeam(String teamName) {
		return getTeam(db.loadObject(Table.TEAM, teamName));
	}
	
	public Team loadTeam(int teamId) {
		return getTeam(db.loadObject(Table.TEAM, teamId, 0));
	}
	
	public Map<Long, Team> loadTeams() {
		return getTeamsMap(db.loadObject(Table.TEAM, 0, 0));
	}
	
	public Map<Long, Team> loadTeams(int divId) {
		return getTeamsMap(db.loadObject(Table.TEAM, 0, divId));
	}
	
	private Team getTeam(Object obj) {
		if (obj != null) {
			((Team)obj).loadExtensions();
			return (Team) obj;
		} else
			return null;
	}
	
	private Map<Long, Team> getTeamsMap(Object obj) {
		if (obj != null) {
			for (Team team : ((Map<Long, Team>)obj).values()) {
				team.loadExtensions();
			}
		
			return (Map<Long, Team>) obj;
		} else
			return null;
	}
	
	/**
	 * Sorts the teams by points, for a tie it's the fewer number of games played
	 * @param teams
	 * @return ArrayList
	 */
	public static ArrayList<Team> sortTeamsByPoints(ArrayList<Team> teams) {
		Collections.sort(teams, new Comparator<Team>() {
			public int compare(Team t1, Team t2) {
				int diff = 0;
				diff = (t2.points - t1.points);
				if (diff == 0 && t1.gamesPlayed != t2.gamesPlayed) {
					//who played less games?
					diff = (t1.gamesPlayed > t2.gamesPlayed) ? 1 : -1;
				}
				
				return diff;
			}
		});
		
		int standingsPos = 1;
		for (Team team : teams) {
			team.standingsPos = standingsPos;
			standingsPos++;
		}
		
		return teams;
	}
	
	/**
	 * Sorts the teams by points, for a tie it's the fewer number of games played
	 * @param teams
	 * @return ArrayList
	 */
	@SuppressWarnings("rawtypes")
	public static Map<Long, Team> sortTeamsMapByPoints(Map<Long, Team> teams) {
		int pos = 1;
		TeamComparator tc = new TeamComparator(teams);
		TreeMap<Long, Team> sorted_map = new TreeMap(tc);
		sorted_map.putAll(teams);
		
		for (Team teamItr : sorted_map.values()) {
			teamItr.standingsPos = pos++;
		}
		
		return sorted_map;
	}
	
/** 
 * DIVISIONS 
 * **/
	
	public static ArrayList<Team> getDivisionSubList(ArrayList<Team> teams, int divisionId) {
		ArrayList<Team> subList = new ArrayList<Team>();
		
		for (Team team : teams) {
			if (team.divisionId == divisionId) {
				subList.add(team);
			}
		}
		
		return subList;
	}
	
	public static ArrayList<Team> sortTeamsByDivision(ArrayList<Team> teams) {
		Collections.sort(teams, new Comparator<Team>() {
			public int compare(Team t1, Team t2) {
				return t2.divisionId - t1.divisionId;
			}
		});
		
		return teams;
	}
	
	public Map<Long, Division> loadDivisions() {
		Object obj = db.loadObject(Table.DIVISION, 0, 0);
		if (obj != null) 
			return (Map<Long, Division>) obj;
		else
			return null;
	}
	
	public Division loadDivision(int divId) {
		Object obj = db.loadObject(Table.DIVISION,  divId, 0);
		if (obj != null)
			return (Division) obj;
		else
			return null;
	}
	
	public Division loadDivision(String divName) {
		Object obj = db.loadObject(Table.DIVISION,  divName);
		if (obj != null)
			return (Division) obj;
		else
			return null;
	}
	
/** 
 * SEASONS 
 * **/
	
	public Map<Long, Season> loadSeasons() {
		Object obj = db.loadObject(Table.SEASON, 0, 0);
		if (obj != null)
			return (Map<Long, Season>) obj;
		else
			return null;
	}
	
	public Season loadSeason(int seasonId) {
		Object obj = db.loadObject(Table.SEASON, seasonId, 0);
		if (obj != null)
			return (Season) obj;
		else
			return null;
	}
	
	public Season loadSeason(String seasonName) {
		Object obj = db.loadObject(Table.SEASON, seasonName);
		if (obj != null)
			return (Season) obj;
		else
			return null;
	}
	
/** 
 * EXTENSIONS 
 * **/
	
	public Extension loadExtension(int extId) {
		Object obj = db.loadObject(Table.EXTENSION, extId, 0);
		if (obj != null)
			return (Extension) obj;
		else
			return null;
	}
	
	public Map<String, Extension> loadExtensions() {
		Object obj = db.loadObject(Table.EXTENSION, 0, 0);
		if (obj != null)
			return (Map<String, Extension>) obj;
		else
			return null;
	}
	
	public Map<String, Extension> loadTeamExtensions(int teamId) {
		Object obj = db.loadObject(Table.EXTENSION, 0, teamId);
		if (obj != null)
			return (Map<String, Extension>) obj;
		else
			return null;
	}
	
	public Map<String, Extension> loadExtensions(int teamId, int extType) {
		Map<String, Extension> extensions = loadTeamExtensions(teamId);
		if (extensions != null) {
			Collection<Extension> forIteration = new HashSet<Extension>(extensions.values());
			for (Extension ext : forIteration) {
				if (ext.extType() != extType)
					extensions.remove(ext.name);
			}
			if (extensions.size() == 0)
				extensions = null;
			
			return extensions;
		} else {
			return null;
		}
	}
	
	public Map<String, Extension> loadExtsByType(int extType) {
		Map<String, Extension> extensions =  loadExtensions();
		if (extensions != null) {
			Collection<Extension> forIteration = new HashSet<Extension>(extensions.values());
			for (Extension ext : forIteration) {
				if (ext.extType() != extType)
					extensions.remove(ext.name);
			}
			if (extensions.size() == 0)
				extensions = null;
			
			return extensions;
		} else {
			return null;
		}
	}
	
	@SuppressWarnings("rawtypes")
	public static class TeamComparator implements Comparator {
		Map base;
		
		public TeamComparator(Map base) {
			this.base = base;
		}
		
		public int compare(Object a, Object b) {
			int diff = 0;
			
			Team teamA = (Team) base.get(a);
			Team teamB = (Team) base.get(b);
			
			diff = teamB.points - teamA.points;
			if (diff == 0) {
				if (teamA.gamesPlayed == teamB.gamesPlayed) {
					if (teamA.extensions.get(Extension.ExtensionConstants.ROW).value == teamB.extensions.get(Extension.ExtensionConstants.ROW).value) {
						if (teamA == teamB) {
							diff = 1;
						} else {
							//goal differential
							int teamADiff = Integer.parseInt(teamA.extensions.get(Extension.ExtensionConstants.GF).value) - Integer.parseInt(teamA.extensions.get(Extension.ExtensionConstants.GA).value); 
							int teamBDiff = Integer.parseInt(teamB.extensions.get(Extension.ExtensionConstants.GF).value) - Integer.parseInt(teamB.extensions.get(Extension.ExtensionConstants.GA).value);
							diff = teamBDiff - teamADiff;
						}
					} else {
						//who has the greater row?
						diff = Integer.parseInt(teamB.extensions.get(Extension.ExtensionConstants.ROW).value) - 
								Integer.parseInt(teamA.extensions.get(Extension.ExtensionConstants.ROW).value);
					}
				} else { 
					//who played less games?
					diff = teamA.gamesPlayed - teamB.gamesPlayed;
				}
			}
			
			return diff;
		}
		
	}
}